define
(
    ["./User",
     "./Task",
     "Common/ObjectUtilities",
     "Common/OrderedChangeIdSet"],
    function(User, 
                 Task,
                 ObjectUtilities,
                 OrderedChangeIdSet)
    {
        return function(id, owner)
        {
            var _id = id;
            var _owner;
            var _users = {};
            var _tasks = new OrderedChangeIdSet();            
            var _elementId = 0;
            var _soundUrl;

            this.getDocumentId = function()
            {
                return _id;
            };

            this.getOwner = function() { return _owner; };
            this.setOwner = function(owner)
            {
                if (!owner)
                {
                    throw "Invalid owner";
                }

                _owner = owner;
            };

            this.getUsers = function()
            {
                var users = [];
                for (index in _users)
                {
                    users.push(_users[index]);
                }
                return users;
            };

            this.getPeers = function(user)
            {
                var users = this.getUsers();
                var index = users.indexOf(user);
                if (index >= 0)
                {
                    users.splice(index, 1);
                }
                return users;
            };

            this.addUser = function(user)
            {
                if (!user)
                {
                    throw "Invalid user";
                }

                _users[user.getSessionId()] = user;
            };

            this.getUser = function(sessionId)
            {
                return _users[sessionId];
            };

            this.createElement = function(taskChangeId, frameChangeId, element)
            {
                var task = _tasks.find(taskChangeId);

                if (!task)
                {
                    // TODO: Return error
                    return;
                }

                return task.createElement(frameChangeId, element);
            };

            this.deleteElements = function(taskChangeId, frameChangeId, changeIds)
            {
                var task = _tasks.find(taskChangeId);

                if (!task)
                {
                    // TODO: Return error
                    return;
                }

                task.deleteElements(frameChangeId, changeIds);
            };

            this.modifyElements = function(taskChangeId, frameChangeId, elements)
            {
                var task = _tasks.find(taskChangeId);

                if (!task)
                {
                    // TODO: Return error
                    return;
                }

                task.modifyElements(frameChangeId, elements);
            }

            this.createTask = function(predecessorTaskId, taskObj)
            {
                var elementId = _elementId++;
                var task = new Task(elementId, taskObj.name, taskObj.description);
                _tasks.add(predecessorTaskId, task);
                taskObj.changeId = elementId;
                return elementId;
            };

            this.createFrame = function(taskChangeId, frameObj, predecessorFrameId)
            {
                var task = _tasks.find(taskChangeId);

                if (!task)
                {
                    // TODO: Return error
                    return;
                }

                return task.createFrame(frameObj, predecessorFrameId);
            };

            this.deleteFrame = function(taskChangeId, frameChangeId)
            {
                var task = _tasks.find(taskChangeId);

                if (!task)
                {
                    // TODO: Return error
                    return;
                }

                task.deleteFrame(frameChangeId);
            };

            this.reorderFrame = function(taskChangeId, frameChangeId, newIndex)
            {
                var task = _tasks.find(taskChangeId);

                if (!task)
                {
                    // TODO: Return error
                    return;
                }

                task.reorderFrame(frameChangeId, newIndex);
            };

            this.addSound = function(soundUrl)
            {
                _soundUrl = soundUrl;
            };

            this.toJSON = function()
            {                
                return {id: _id, owner: _owner, users: ObjectUtilities.toArray(_users), tasks: _tasks, soundUrl: _soundUrl};
            };            
            
            this.setOwner(owner);
            this.addUser(owner);
        };
    }
);